#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

#include <boost/thread/xtime.hpp>
#include <boost/thread/thread.hpp>

#include "base/logging.h"
#include "fcgi_service/fcgi_service.h"

using namespace std;
using namespace fcgi;


class LoadRequest : public Request {
public:
  LoadRequest(FCGX_Request* r) : Request(r) {}
  virtual bool Response() {
    if(!fcgi_out_) {
      LOG_INFO("fcgi_out NULL");
      return false;
    }
    int article_id = GetQueryInt("aid", -1);
    FCGX_PutS("Content-type: text/html\r\n\r\n", fcgi_out_);

    if (article_id > 0) {
      ArticleStatCache::Instance().AddPv(article_id, 1);
      stat = ArticleStatCache::Instance().GetStat(article_id);
    }

    FCGX_FPrintF(fcgi_out_, "{\"pv\":%d, \"count\":%d, \"score\":%.2f}", stat.pv, 
        stat.rank_count, stat.average_score());

    return true;
  }
};

class PvRequest : public Request {
public:
  PvRequest(FCGX_Request* r) : Request(r) {}
  virtual bool Response() {
    if(!fcgi_out_) {
      LOG_INFO("fcgi_out NULL");
      return false;
    }
    int article_id = GetQueryInt("aid", -1);
    FCGX_PutS("Content-type: text/html\r\n\r\n", fcgi_out_);
    if (article_id > 0) {
      ArticleStatCache::Instance().AddPv(article_id, 1);
    }
    FCGX_FPrintF(fcgi_out_, "%d", article_id);
    return true;
  }
};

class AddCountRequest : public Request {
public:
  RankRequest(FCGX_Request* r) : Request(r) {}
  virtual bool Response() {
    if (!fcgi_out_) {
      LOG_INFO("fcgi_out NULL");
      return false;
    }

    int business_type = GetQueryInt("t", -1);
    int64_t business_id = GetQueryInt("id", -1);
    int delta = GetQueryInt("d", -1);

    FCGX_PutS("Content-type: text/html\r\n\r\n", fcgi_out_);

    StatInfo stat;
    if (article_id > 0) {
      stat = ArticleStatCache::Instance().Rank(article_id, score);
    }
    FCGX_FPrintF(fcgi_out_, "{\"count\":%d, \"score\":%.2f}", stat.rank_count, stat.average_score());
    return true;
  }
};

class DemoRequest : public Request {
public:
  DemoRequest(FCGX_Request* r) : Request(r) {}
  virtual bool Response();
};

bool DemoRequest::Response() {
  static int count = 0;
  if(!fcgi_out_) {
    cout << "remove notify fcgi_out null";
    return false;
  }

  stringstream rsp_header;
  rsp_header << "Content-type: text/html\r\n" << "Set-Cookie: count="
             << ++count << "\r\n\r\n";
  FCGX_PutS(rsp_header.str().c_str(), fcgi_out_);

  string rsp_body;
  rsp_body += "<span style=\"color:red\">query:</span>:</br>";
  for(map<string, string>::const_iterator it = query_map_.begin(); it != query_map_.end(); ++it) {
    rsp_body += it->first;
    rsp_body += ":";
    rsp_body += it->second;
    rsp_body += "</br>";
  }

  rsp_body += "<span style=\"color:red\">cookies:</span>:</br>";
  for(map<string, string>::const_iterator it = cookie_map_.begin(); it != cookie_map_.end(); ++it) {
    rsp_body += it->first;
    rsp_body += ":";
    rsp_body += it->second;
    rsp_body += "</br>";
  }

  FCGX_PutS(rsp_body.c_str(), fcgi_out_);
  return true;
}

class DemoRequestFactory : public RequestFactory {
public:
  virtual RequestPtr Create(FCGX_Request * r) {
    char * path = FCGX_GetParam("SCRIPT_NAME", r->envp);
    RequestPtr req;
    if (path) {
      if (strcmp(path, "/cgi/demo") == 0) {
        req = RequestPtr(new DemoRequest(r));
      } else if (strcmp(path, "/cgi/stat-load") == 0) {
        req = RequestPtr(new LoadRequest(r));
      } else if (strcmp(path, "/cgi/stat-pv") == 0) {
        req = RequestPtr(new PvRequest(r));
      } else if (strcmp(path, "/cgi/stat-rank") == 0) {
        req = RequestPtr(new RankRequest(r));
      }
    }
    return req;
  }
};

int main(){
  LOG_INIT("./article_stat.log", "DEBUG");
  string listen("127.0.0.1:19000");
  FcgiServer * fcgi_server = new FcgiServer(listen, 16);
  printf("start listen on %s\n", listen.c_str());
  // FcgiServer * fcgi_server = new FcgiServer("10.22.206.157:19000", 16);
  fcgi_server->RegisterRequestFactory(RequestFactoryPtr(new DemoRequestFactory()));
  fcgi_server->Start(true); // 本线程也处理 fcgi 请求，不退出
  return 0;
}

